home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 25
/
Mac Magazin and MacEasy Magazine CD - Issue 25.iso
/
Grafik & Text
/
BibTeX
/
Source code
/
StdPrefsLib
/
StdPrefsLib.c
< prev
next >
Wrap
Text File
|
1995-10-23
|
34KB
|
1,330 lines
/*
File: StdPrefsLib.c
Contains: Standard preferences library routines.
Refer to develop Issue 18, "The Right Way to Implement
Preferences Files", for additional details on this code.
Written by: Gary Woodcock
Copyright: © 1993-94 by Apple Computer, Inc.
Change History (most recent first):
3/3/94 Version 1.0.
Notes: This code uses Apple's Universal Interfaces for C.
Send bug reports to Gary Woodcock at AOL: gwoodcock
or Internet: gwoodcock@aol.com.
*/
//-----------------------------------------------------------------------
// Includes
#include "CompileFlags.h"
#include "StdPrefsLib.h"
#include "StdPrefsLibPrivate.h"
#include "DebugUtils.h"
#include "FSpCompat.h"
#include "MoreFilesExtras.h"
#include "Search.h"
#include <Errors.h>
#include <Files.h>
#include <Finder.h>
#include <Folders.h>
#include <Memory.h>
#include <Resources.h>
#include <Script.h>
// #include <SysEqu.h>
#include <ToolUtils.h>
//-----------------------------------------------------------------------
// Private constants
enum
{
kApplicationMissingMessageStrID = -16397
};
//-----------------------------------------------------------------------
// Private prototypes
static OSErr
GetPrefsDirVRefNumAndDirID (ConstStr31Param folderName,
Boolean createFolder, short *vRefNum, long *dirID);
static OSErr
GetPreferencesFileFSSpec (OSType creator, OSType fileType,
FSSpec *file);
static Boolean
DirIDInPrefsDir (short vRefNum, long dirID, long prefsDirID);
static short
FindVRefNum (short fRefNum);
static unsigned long
GetVolFreeSpace (short vRefNum);
static unsigned long
GetVAllocationBlockSize (short vRefNum);
static OSErr
GetDirPathName (short vRefNum, long dirID, Str255 pathName);
static OSErr
CopyString (ConstStr255Param theSourceStr, Str255 theDestStr);
static OSErr
CatenateStrings (ConstStr255Param theFirstStr,
ConstStr255Param theSecondStr, Str255 theCatenatedStr);
static OSErr
CopyResource (ResType theType, short theID, FSSpec *fileToCopyTo);
//-----------------------------------------------------------------------
pascal OSErr
NewPreferencesFile (OSType creator, OSType fileType,
ConstStr31Param fileName, ConstStr31Param folderName,
ConstStr31Param ownerName)
{
OSErr result = noErr;
// Make sure parameters are valid
if (fileName != nil)
{
long dirID;
short vRefNum;
// Get the vRefNum and dirID for the folder to put the preferences file in
result = GetPrefsDirVRefNumAndDirID (folderName, true, &vRefNum, &dirID);
if (result == noErr)
{
short savedResFile = CurResFile();
// Create the file
HCreateResFile (vRefNum, dirID, fileName);
result = ResError();
if (result == noErr)
{
FInfo info;
// Set the file type and creator, and lock the name
result = HGetFInfo (vRefNum, dirID, fileName, &info);
if (result == noErr)
{
info.fdType = fileType;
info.fdCreator = creator;
info.fdFlags |= kNameLocked;
result = HSetFInfo (vRefNum, dirID, fileName, &info);
if (result == noErr)
{
// Should we add an application-missing message string?
if (ownerName != nil)
{
Str255 preamble;
Str255 postamble;
// Build the application-missing message string
GetIndString (preamble, kStdPrefsLibStrsID, kPreambleStrID);
GetIndString (postamble, kStdPrefsLibStrsID, kPostambleStrID);
if ((preamble != nil) && (postamble != nil))
{
result = CatenateStrings (preamble, *((Str255 *)ownerName), preamble);
if (result == noErr)
{
result = CatenateStrings (preamble, postamble, preamble);
if (result == noErr)
{
short fRefNum;
// Open the new file
result = OpenPreferencesFile (creator, fileType, &fRefNum);
if (result == noErr)
{
Handle messageHdl;
// Add the application-missing message string
PtrToHand ((Ptr)&preamble, &messageHdl, preamble[0] + 1);
if ((result = MemError()) == noErr)
{
short resID = kApplicationMissingMessageStrID;
result = WritePreference (fRefNum, 'STR ', &resID, messageHdl);
DisposeHandle (messageHdl);
result = MemError();
FailMessage (result != noErr, NewPreferencesFile: DisposeHandle failed.);
}
else
{
DebugMessage (NewPreferencesFile: PtrToHand failed.);
}
// Close up shop
result = ClosePreferencesFile (fRefNum);
}
}
}
}
else // GetIndString failed
{
result = -1L;
DebugMessage (NewPreferencesFile: GetIndString failed.);
}
}
}
else // HSetFInfo failed
{
DebugMessage (NewPreferencesFile: HSetFInfo failed.);
}
}
else // HGetFInfo failed
{
DebugMessage (NewPreferencesFile: HGetFInfo failed.);
}
}
else // HCreateResFile failed
{
DebugMessage (NewPreferencesFile: HCreateResFile failed.);
}
// Restore the resource file
UseResFile (savedResFile);
result = ResError();
FailMessage (result != noErr, NewPreferencesFile: UseResFile failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (NewPreferencesFile: Bad parameter);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
OpenPreferencesFile (OSType creator, OSType fileType, short *fRefNum)
{
OSErr result = noErr;
// Make sure parameters are valid
if (fRefNum != nil)
{
FSSpec prefsFSSpec;
short savedResFile = CurResFile();
// Get the FSSpec for the preferences file
result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
if (result == noErr)
{
// Open it up
short theFRefNum = FSpOpenResFileCompat (&prefsFSSpec, fsRdWrPerm);
result = ResError();
if (result == noErr)
{
*fRefNum = theFRefNum;
// Restore the resource file
UseResFile (savedResFile);
result = ResError();
FailMessage (result != noErr, OpenPreferencesFile: UseResFile failed.);
}
else // FSpOpenResFileCompat failed
{
DebugMessage (OpenPreferencesFile: FSpOpenResFileCompat failed.);
}
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (OpenPreferencesFile: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
ClosePreferencesFile (short fRefNum)
{
OSErr result = noErr;
// Make sure parameters are valid
if (fRefNum != -1)
{
// Close it
CloseResFile (fRefNum);
result = ResError();
FailMessage (result != noErr, ClosePreferencesFile: CloseResFile failed.);
}
else // Bad parameter
{
result = paramErr;
DebugMessage (ClosePreferencesFile: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
DeletePreferencesFile (OSType creator, OSType fileType)
{
FSSpec prefsFSSpec;
OSErr result;
// Get the preferences file FSSpec
result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
if (result == noErr)
{
// Delete it
result = FSpDeleteCompat (&prefsFSSpec);
FailMessage (result != noErr, DeletePreferencesFile: FSpDeleteCompat failed.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
DeletePreferencesFolder (ConstStr31Param folderName)
{
OSErr result = noErr;
// Make sure the parameters are valid
if (folderName != nil)
{
long dirID;
short vRefNum;
// Get the vRefNum and dirID of the preferences folder
result = GetPrefsDirVRefNumAndDirID (folderName, false, &vRefNum, &dirID);
if (result == noErr)
{
Str255 pathName;
// Get the path to the folder
result = GetDirPathName (vRefNum, dirID, pathName);
if (result == noErr)
{
// Delete it
result = DeleteDirectory (vRefNum, dirID, (StringPtr)pathName);
FailMessage (result != noErr, DeletePreferencesFolder: DeleteDirectory failed.);
}
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (DeletePreferencesFolder: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal Boolean
PreferencesFileExists (OSType creator, OSType fileType)
{
FSSpec prefsFSSpec;
OSErr result = noErr;
// If file doesn't exist, fnfErr will be returned
result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
return (result == noErr);
}
//-----------------------------------------------------------------------
pascal OSErr
GetPreferencesFileVersion (short fRefNum, short versID,
NumVersion *numVersion, short *regionCode,
ConstStr255Param shortVersionStr, ConstStr255Param longVersionStr)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((fRefNum != -1) && ((versID == kVers1) || (versID == kVers2)) &&
(numVersion != nil) && (regionCode != nil))
{
VersRecHndl versHdl;
short resID = versID;
// Read the version resource
result = ReadPreference (fRefNum, 'vers', &resID, (Handle *)&versHdl);
if ((result == noErr) && (versHdl != nil))
{
*numVersion = (**versHdl).numericVersion;
*regionCode = (**versHdl).countryCode;
// Note that the long version string is packed at the end of the
// short version string - this is the format for the 'vers'
// resource
BlockMoveData ((Ptr)((**versHdl).shortVersion), (Ptr)shortVersionStr,
(**versHdl).shortVersion[0] + 1);
BlockMoveData ((Ptr)&((**versHdl).shortVersion[shortVersionStr[0] + 1]),
(Ptr)longVersionStr, (**versHdl).shortVersion[shortVersionStr[0] + 1] + 1);
// Clean up
DisposeHandle ((Handle) versHdl);
result = MemError();
FailMessage (result != noErr, GetPreferencesFileVersion: DisposeHandle failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (GetPreferencesFileVersion: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
SetPreferencesFileVersion (short fRefNum, short versID,
NumVersion *numVersion, short regionCode,
ConstStr255Param shortVersionStr, ConstStr255Param longVersionStr)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((fRefNum != -1) && ((versID == kVers1) || (versID == kVers2)) &&
(numVersion != nil))
{
VersRecHndl versHdl = (VersRecHndl) NewHandleClear (sizeof (VersRec));
if (versHdl != nil)
{
short resID = versID;
(**versHdl).numericVersion = *numVersion;
(**versHdl).countryCode = regionCode;
// Note that the long version string is packed at the end of the
// short version string - this is the format for the 'vers'
// resource
BlockMoveData ((Ptr)(shortVersionStr), (Ptr)((**versHdl).shortVersion),
shortVersionStr[0] + 1);
BlockMoveData ((Ptr)(longVersionStr),
(Ptr)&((**versHdl).shortVersion[shortVersionStr[0] + 1]),
longVersionStr[0] + 1);
// Write the version resource
result = WritePreference (fRefNum, 'vers', &resID, (Handle) versHdl);
}
else // Couldn't get any memory
{
result = MemError();
DebugMessage (SetPreferencesFileVersion: NewHandleClear failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (SetPreferencesFileVersion: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
ReadPreference (short fRefNum, ResType resourceType, short *resourceID,
Handle *preference)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((fRefNum != -1) && (preference != nil))
{
short savedResFile = CurResFile(); // Save off current resource file
// Use this file
UseResFile (fRefNum);
result = ResError();
if (result == noErr)
{
// See if the resource is around
if ((resourceID != nil) && (*resourceID != 0))
{
// Get the resource with the specified ID
*preference = Get1Resource (resourceType, *resourceID);
}
else
{
// Get the first resource of this type
*preference = Get1IndResource (resourceType, 1);
if ((*preference != nil) && (resourceID != nil))
{
Str255 dummy1;
ResType dummy2;
// Get the resource ID
GetResInfo (*preference, resourceID, &dummy2, dummy1);
}
}
// Did we get a resource successfully?
if (((result = ResError()) == noErr) && (*preference != nil))
{
// Detach it
DetachResource (*preference);
result = ResError();
FailMessage (result != noErr, ReadPreference: DetachResource failed.);
}
else // Get1Resource failed
{
result = resNotFound;
DebugMessage (ReadPreference: Get1Resource failed.);
}
// Restore the resource file
UseResFile (savedResFile);
result = ResError();
FailMessage (result != noErr, ReadPreference: UseResFile failed.);
}
else // UseResFile failed
{
DebugMessage (ReadPreference: UseResFile failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (ReadPreference: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
WritePreference (short fRefNum, ResType resourceType, short *resourceID,
Handle preference)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((fRefNum != -1) && (preference != nil))
{
Handle localPref = preference;
// Make a local copy of this preference
result = HandToHand (&localPref);
if (result == noErr)
{
Handle oldPref = nil;
Size prefSize = GetHandleSize (localPref); // Get size of preference to be added
Size existingPrefSize = prefSize;
long freeSpaceOnDisk;
short vRefNum = FindVRefNum (fRefNum);
short savedResFile = CurResFile(); // Save off current resource file
short resID;
// Get free disk space
freeSpaceOnDisk = GetVolFreeSpace (vRefNum);
// Use this file
UseResFile (fRefNum);
result = ResError();
if (result == noErr)
{
// See if this resource is already around
if ((resourceID != nil) && (*resourceID != 0))
{
// Get the resource with the specified ID
oldPref = Get1Resource (resourceType, *resourceID);
}
// Did we find an existing resource?
if (oldPref != nil)
{
// How big is it?
existingPrefSize = GetHandleSize (oldPref);
// Make sure that there's enough disk space available to
// accomodate the resource that's replacing the old one -
// if there's not, leave the old one in place, and return an error
// We'll leave at least one allocation block left for the system
if ((prefSize > existingPrefSize) &&
(prefSize + GetVAllocationBlockSize (FindVRefNum (fRefNum)) > freeSpaceOnDisk))
{
result = dskFulErr;
DebugMessage (WritePreference: Not enough disk space to write resource.);
}
else
{
// Get rid of it
RemoveResource (oldPref);
if ((result = ResError()) == noErr)
{
// Update the file
UpdateResFile (fRefNum);
result = ResError();
FailMessage (result != noErr, WritePreference: UpdateResFile failed.);
}
else // RmveResource failed
{
DebugMessage (WritePreference: RmveResource failed.);
}
// Clean up
DisposeHandle (oldPref);
result = MemError();
FailMessage (result != noErr, WritePreference: DisposeHandle failed.);
}
}
if (result == noErr)
{
// Make sure there's room
if (prefSize + GetVAllocationBlockSize (FindVRefNum (fRefNum)) > freeSpaceOnDisk)
{
result = dskFulErr;
DebugMessage (WritePreference: Not enough disk space to write resource.);
}
else
{
// Figure out the resource ID to use
if (resourceID != nil)
{
if (*resourceID == 0)
{
// Get a unique resource ID
resID = Unique1ID (resourceType);
*resourceID = resID;
}
else
{
resID = *resourceID;
}
}
else
{
// Get a unique resource ID
resID = Unique1ID (resourceType);
}
// Add the resource
AddResource (localPref, resourceType, resID, "\p");
if ((result = ResError()) == noErr)
{
// Write it to the file
WriteResource (localPref);
FailMessage ((result = ResError()) != noErr, WritePreference:
WriteResource failed.);
// Clean up
ReleaseResource (localPref);
FailMessage ((result = ResError()) != noErr, WritePreference:
ReleaseResource failed.);
}
else // AddResource failed
{
DebugMessage (WritePreference: AddResource failed.);
}
}
}
// Restore the resource file
UseResFile (savedResFile);
result = ResError();
FailMessage (result != noErr, WritePreference: UseResFile failed.);
}
else // UseResFile failed
{
DebugMessage (WritePreference: UseResFile failed.);
}
}
else // HandToHand failed
{
DebugMessage (WritePreference: HandToHand failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (WritePreference: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
pascal OSErr
DeletePreference (short fRefNum, ResType resourceType, short resourceID)
{
OSErr result = noErr;
// Make sure parameters are valid
if (fRefNum != -1)
{
Handle prefToKill;
short savedResFile = CurResFile(); // Save off the current resource file
// Use this file
UseResFile (fRefNum);
result = ResError();
if (result == noErr)
{
// Are there any of these resources around?
if (Count1Resources (resourceType) > 0)
{
// See if this resource is around
if (resourceID != 0)
{
// Get the resource with the specified ID
prefToKill = Get1Resource (resourceType, resourceID);
}
else
{
// Get the first resource of this type
prefToKill = Get1IndResource (resourceType, 1);
}
// Did we find a resource to delete?
if (prefToKill != nil)
{
// Remove it
RemoveResource (prefToKill);
if ((result = ResError()) == noErr)
{
// Update the file
UpdateResFile (fRefNum);
FailMessage ((result = ResError()) != noErr, DeletePreference:
UpdateResFile failed.);
}
else // RmveResource failed
{
DebugMessage (DeletePreference: RmveResource failed.);
}
// Clean up
DisposeHandle (prefToKill);
result = MemError();
FailMessage (result != noErr, DeletePreference: DisposeHandle failed.);
}
}
else // Couldn't find this resource
{
result = resNotFound;
DebugMessage (DeletePreference: Resource not found.);
}
// Restore the resource file
UseResFile (savedResFile);
result = ResError();
FailMessage (result != noErr, DeletePreference: UseResFile failed.);
}
else // UseResFile failed
{
DebugMessage (DeletePreference: UseResFile failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (DeletePreference: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
static OSErr
GetPrefsDirVRefNumAndDirID (ConstStr31Param folderName,
Boolean createFolder, short *vRefNum, long *dirID)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((vRefNum != nil) && (dirID != nil))
{
long id;
// Locate the Preferences folder
result = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
vRefNum, &id);
if (result == fnfErr)
{
// No Preferences folder found, try to find the System Folder
result = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
vRefNum, &id);
if (result != noErr)
{
// Couldn't find the System Folder - we're hosed
DebugMessage (GetPrefsDirVRefNumAndDirID: FindFolder failed.);
goto BAIL;
}
}
else if (result != noErr)
{
// Got some other kind of bad error from FindFolder when trying
// to find the Preferences folder
DebugMessage (GetPrefsDirVRefNumAndDirID: FindFolder failed.);
goto BAIL;
}
// Are we using a custom preferences folder?
if (folderName != nil)
{
DirInfo info;
// See if the specified custom preferences folder is around
info.ioNamePtr = (StringPtr) folderName;
info.ioVRefNum = *vRefNum;
info.ioDrDirID = id;
info.ioFDirIndex = 0;
result = PBGetCatInfoSync((CInfoPBPtr)&info);
if (result == noErr)
{
*dirID = info.ioDrDirID;
}
else if ((result == fnfErr) && createFolder)
{
// Try to create the specified custom preferences folder
result = DirCreate (*vRefNum, id, folderName, dirID);
FailMessage (result != noErr, GetPrefsDirVRefNumAndDirID: DirCreate failed.);
}
else // PBGetCatInfo failed
{
DebugMessage (GetPrefsDirVRefNumAndDirID: PBGetCatInfo failed.);
}
}
else // Not using a custom preferences folder
{
*dirID = id;
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (GetPrefsDirVRefNumAndDirID: Bad parameter.);
}
BAIL:
return (result);
}
//-----------------------------------------------------------------------
static OSErr
GetPreferencesFileFSSpec (OSType creator, OSType fileType,
FSSpec *file)
{
OSErr result = noErr;
// Make sure parameters are valid
if (file != nil)
{
long systemFolderDirID;
long prefsFolderDirID;
short vRefNum;
Boolean hasPrefsDir;
Boolean foundIt = false;
// Find the Preferences folder dirID
result = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
&vRefNum, &prefsFolderDirID);
hasPrefsDir = (result == noErr);
// Find the System Folder dirID
result = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
&vRefNum, &systemFolderDirID);
// Did we find the System Folder OK?
if (result == noErr)
{
FSSpec possibleMatch;
long numMatches;
Boolean firstSearch = true;
// Check the Preferences folder first
if (hasPrefsDir)
{
// Loop through the possible candidates until a candidate is found
do
{
result = CreatorTypeFileSearch (nil, vRefNum, creator, fileType,
(FSSpecPtr) &possibleMatch, 1L, &numMatches, firstSearch);
firstSearch = false;
// Did we get a match?
if (numMatches == 1)
{
// Check to see if this file is within the Preferences
// folder or any of its nested folders
if (DirIDInPrefsDir (vRefNum, possibleMatch.parID, prefsFolderDirID))
{
// Got one!
foundIt = true;
break;
}
}
}
while ((result == noErr) || (result == catChangedErr));
}
// If we didn't find it in the Preferences folder, check the
// System Folder
if (!foundIt)
{
// Loop through the possible candidates until a candidate is found
firstSearch = true;
do
{
result = CreatorTypeFileSearch (nil, vRefNum, creator, fileType,
(FSSpecPtr) &possibleMatch, 1L, &numMatches, firstSearch);
firstSearch = false;
// Did we get a match?
if ((numMatches == 1) && (possibleMatch.parID == systemFolderDirID))
{
// Got one!
foundIt = true;
break;
}
}
while ((result == noErr) || (result == catChangedErr));
}
// If we found one, return it
if (foundIt)
{
*file = possibleMatch;
}
else // Didn't find a preferences file with the specified creator and file type
{
result = fnfErr;
DebugMessage (GetPreferencesFileFSSpec: Could not find preferences file.);
}
}
else // Couldn't find the System Folder
{
DebugMessage (GetPreferencesFileFSSpec: FindFolder failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (GetPreferencesFileFSSpec: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
static Boolean
DirIDInPrefsDir (short vRefNum, long dirID, long prefsDirID)
{
OSErr result = noErr;
Boolean inPrefsDir = false;
// Make sure parameters are valid
if (vRefNum < 0)
{
// Is the dirID of the directory the same as the Preferences
// folder dirID?
if (dirID == prefsDirID)
{
inPrefsDir = true;
}
else // Nope, we need to follow the path up toward the root
{
DirInfo info;
Str255 dirName;
Str255 pathName;
// Initialize some stuff
pathName[0] = '\0';
info.ioDrParID = dirID;
info.ioNamePtr = dirName;
// Walk the path upward, one directory at a time,
// until we either determine that the directory is
// in the Preferences folder, or until we hit the
// root directory (this always has a dirID of 2)
do
{
info.ioVRefNum = vRefNum;
info.ioFDirIndex = -1;
info.ioDrDirID = info.ioDrParID;
result = PBGetCatInfoSync((CInfoPBPtr)&info);
if (result == noErr)
{
// Is this the Preferences folder?
if (info.ioDrParID == prefsDirID)
{
// Yep, we can leave now
inPrefsDir = true;
break;
}
else // Nope, append this string to the path name and try again
{
result = CatenateStrings (dirName, "\p:", dirName);
if (result == noErr)
{
result = CatenateStrings (dirName, pathName, pathName);
if (result != noErr)
{
// CatenateStrings failed
break;
}
}
else // CatenateStrings failed
{
break;
}
}
}
else // PBGetCatInfo failed
{
DebugMessage (DirIDInPrefsDir: PBGetCatInfo failed.);
break;
}
}
while (info.ioDrDirID != 2);
}
}
else // Bad parameter
{
DebugMessage (DirIDInPrefsDir: Bad parameter.);
}
return (inPrefsDir);
}
//-----------------------------------------------------------------------
static short
FindVRefNum (short fRefNum)
{
OSErr result = noErr;
short vRefNum = 0;
// Make sure parameters are valid
if (fRefNum != -1)
{
FCBPBRec fcbInfo;
Str63 fName;
// Set up parameter block
fcbInfo.ioNamePtr = fName;
fcbInfo.ioVRefNum = 0;
fcbInfo.ioRefNum = fRefNum;
fcbInfo.ioFCBIndx = 0;
result = PBGetFCBInfoSync (&fcbInfo);
if (result == noErr)
{
vRefNum = fcbInfo.ioFCBVRefNum;
}
else // PBGetFCBInfoSync failed
{
DebugMessage (FindVRefNum: PBGetFCBInfoSync failed.);
}
}
else // Bad parameter
{
DebugMessage (FindVRefNum: Bad parameter.);
}
return (vRefNum);
}
//-----------------------------------------------------------------------
static unsigned long
GetVolFreeSpace (short vRefNum)
{
HParamBlockRec pb;
OSErr result = noErr;
pb.volumeParam.ioNamePtr = nil; // We don't care about the name
pb.volumeParam.ioVRefNum = vRefNum;
pb.volumeParam.ioVolIndex = 0; // Use ioVRefNum only
result = PBHGetVInfoSync(&pb);
if (result == noErr)
{
// Calculate the free space in bytes
return (pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz);
}
else // PBHGetVInfo failed
{
DebugMessage (GetVolFreeSpace: PBHGetVInfo failed.);
return (0L);
}
}
//-----------------------------------------------------------------------
static unsigned long
GetVAllocationBlockSize (short vRefNum)
{
HParamBlockRec pb;
OSErr result = noErr;
pb.volumeParam.ioNamePtr = nil; // We don't care about the name
pb.volumeParam.ioVRefNum = vRefNum;
pb.volumeParam.ioVolIndex = 0; // Use ioVRefNum only
result = PBHGetVInfoSync(&pb);
if (result == noErr)
{
return (pb.volumeParam.ioVAlBlkSiz);
}
else
{
return (0L);
}
}
//-----------------------------------------------------------------------
static OSErr
GetDirPathName (short vRefNum, long dirID, Str255 pathName)
{
OSErr result = noErr;
// Make sure parameters are valid
if (vRefNum < 0)
{
DirInfo info;
Str255 dirName;
// Initialize some stuff
pathName[0] = '\0';
info.ioDrParID = dirID;
info.ioNamePtr = dirName;
// Walk the path upward, one directory at a time,
// until we hit the root directory (this always
// has a dirID of 2)
do
{
info.ioVRefNum = vRefNum;
info.ioFDirIndex = -1;
info.ioDrDirID = info.ioDrParID;
result = PBGetCatInfoSync((CInfoPBPtr)&info);
if (result == noErr)
{
result = CatenateStrings (dirName, "\p:", dirName);
if (result == noErr)
{
result = CatenateStrings (dirName, pathName, pathName);
if (result != noErr)
{
// CatenateStrings failed
break;
}
}
else // CatenateStrings failed
{
break;
}
}
else // PBGetCatInfo failed
{
DebugMessage (GetDirPathName: PBGetCatInfo failed.);
break;
}
}
while (info.ioDrDirID != 2);
}
else // Bad parameter
{
result = paramErr;
DebugMessage (GetDirPathName: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
static OSErr
CopyString (ConstStr255Param theSourceStr, Str255 theDestStr)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((theSourceStr != nil) && (theDestStr != nil))
{
BlockMoveData ((Ptr)theSourceStr, (Ptr)theDestStr, theSourceStr[0] + 1);
}
else // Bad parameter
{
result = paramErr;
DebugMessage (StrCopy: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
static OSErr
CatenateStrings (ConstStr255Param theFirstStr,
ConstStr255Param theSecondStr, Str255 theCatenatedStr)
{
OSErr result = noErr;
// Make sure parameters are valid
if ((theFirstStr != nil) && (theSecondStr != nil) &&
(theCatenatedStr != nil))
{
Str255 catenatedStr;
Str255 secondStr;
long tempSize;
short combinedLength = theFirstStr[0] + theSecondStr[0];
short secondStrLength = theSecondStr[0];
// Can both strings fit in a Str255?
if (combinedLength > 255)
{
// Nope, let's shorten the second string to fit
secondStrLength = 255 - theFirstStr[0];
}
// Copy the strings
BlockMoveData ((Ptr)theFirstStr, (Ptr)catenatedStr, theFirstStr[0] + 1);
BlockMoveData ((Ptr)theSecondStr, (Ptr)secondStr, secondStrLength + 1);
// Copy the second string to the end of the first string
tempSize = catenatedStr[0];
catenatedStr[0] += secondStr[0];
BlockMoveData ((Ptr)&secondStr[1], (Ptr)&catenatedStr[tempSize + 1],
secondStr[0]);
// Copy the catenated string back out
BlockMoveData ((Ptr)catenatedStr, (Ptr)theCatenatedStr,
catenatedStr[0] + 1);
}
else // Bad parameter
{
result = paramErr;
DebugMessage (StrCatenate: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------
static OSErr
CopyResource (ResType theType, short theID, FSSpec *fileToCopyTo)
{
OSErr result = noErr;
// Make sure parameters are valid
if (fileToCopyTo != nil)
{
Handle resToBeCopied = GetResource (theType, theID);
short appResRefNum;
if ((result = ResError()) == noErr)
{
// Get the application's resource refNum
appResRefNum = LMGetCurApRefNum();
if ((resToBeCopied != nil) &&
(appResRefNum == HomeResFile (resToBeCopied)))
{
Handle resToCopyTo;
short resAttributes;
short copyToFileResRefNum;
short savedResFile = CurResFile();
// Get the attributes of the resource to be copied
resAttributes = GetResAttrs (resToBeCopied);
// Detach the resource to be coped
DetachResource (resToBeCopied);
if ((result = ResError()) == noErr)
{
// Open the file to copy to
copyToFileResRefNum = FSpOpenResFile (fileToCopyTo, fsRdWrPerm);
if ((result = ResError()) == noErr)
{
// Set the resource refNum
UseResFile (copyToFileResRefNum);
// Check for existing resources with this type and ID in
// the file we're copying to, and remove any we find
do
{
// Get a resource
resToCopyTo = GetResource (theType, theID);
// Is the resource's res file the same as the
// file we're trying to copy to?
if (HomeResFile (resToCopyTo) == copyToFileResRefNum)
{
// Remove it
RemoveResource (resToCopyTo);
FailMessage ((result = ResError()) != noErr, CopyResource: RmveResource failed.);
DisposeHandle (resToCopyTo);
FailMessage ((result = MemError()) != noErr, CopyResource: DisposeHandle failed.);
}
}
while (HomeResFile (resToCopyTo) != copyToFileResRefNum);
// Add the resource
AddResource (resToBeCopied, theType, theID, "\p");
if ((result = ResError()) == noErr)
{
// Set up the resource's attributes
SetResAttrs (resToBeCopied, resAttributes);
ChangedResource (resToBeCopied);
FailMessage ((result = ResError()) != noErr, CopyResource: ChangedResource failed.);
}
// Close the file
CloseResFile (copyToFileResRefNum);
// Restore resource file
UseResFile (savedResFile);
}
else // FSpOpenResFile failed
{
DebugMessage (CopyResource: FSpOpenResFile failed.);
}
}
else // DetachResource failed
{
DebugMessage (CopyResource: DetachResource failed.);
}
}
}
else // GetResource failed
{
DebugMessage (CopyResource: GetResource failed.);
}
}
else // Bad parameter
{
result = paramErr;
DebugMessage (CopyResource: Bad parameter.);
}
return (result);
}
//-----------------------------------------------------------------------